/*
 * @Author: your name
 * @Date: 2019-12-06 09:35:42
 * @LastEditTime: 2019-12-06 11:48:36
 * @LastEditors: Please set LastEditors
 * @Description: In User Settings Edit
 * @FilePath: \js\实用技巧\stringtoNumber.js
 */

// 利用*1 来转换
// console.log('32'*1)
// console.log('ds'*1)
// console.log(null*1)
// console.log(undefined*1)

// 利用+ '' 来转换+++++++++
// console.log(+'32')
// console.log(+'ds')
// console.log(+ { valueOf : ()=> '3'})


// object 转string
// console.log('the Math object' + Math)
// let person = {
//     name:"Dovey",
//     birthday:new Date('1992-10-20')
// }
// console.log("Object:"+JSON.stringify(person))

//使用Boolean 过滤数组中的所有假值
// const compact = arr=>arr.filter(Boolean)
// console.log(compact([0,1,false,2,'',3,'a','e'*23,NaN,'2',34]))

// 双位运算符~~ 正数类似与Math.floor 负数结果类似于：Math.ceil
// console.log(~~4.9) 
// console.log(Math.floor(4.9)) 
// console.log(Math.ceil(~~-4.5));

// 短路运算符 && ||
// 用来进行简单的判断，取代冗长的 if语句：
// let variable = param && param.prop
// 如果 param如果为真值则返回 param.prop属性，否则返回 param这个假值，这样在某些地方防止 param为 undefined的时候还取其属性造成报错。

// 取整 | 0
// console.log( 1.3  | 0 )
// console.log( -1.9 | 0 );

// 判断奇偶数 & 1
// console.log( !!( 3 & 1))  // true 是奇数
// console.log( !!( 2 & 1))  // false
// console.log( !!( 1 & 1))  // true
// console.log( !!( 4 & 1))  // false


// 函数默认值 传入参数为 undefined或者不传入的时候会使用默认参数，但是传入 null还是会覆盖默认参数。
// let func = (l,m=3,n=4) => (l*m*n);
// console.log(func(2))

// 强制参数 如果不向函数参数传值，那么JS 会将函数参数设置为 undefined。其它一些语言则会发出警告或错误。要执行参数分配，可以使用 if语句抛出未定义的错误，或者可以利用 强制参数。
// mandatory = ( ) => {
//     throw new Error('Missing parameter!');
// }

// foo = (bar = mandatory( )) => { // 这里如果不传入参数，就会执行manadatory函数报出错误
//     return bar;
// }
// foo()

// 隐式返回值
// function func(...n1){
//     return Math.max(...n1)  // Math.max 返回两个数中最大的数
// }
// funcUpdate = (...n)=>(Math.max(...n));
// console.log(Math.max(1,2))
// console.log(func(3,4,5,6,7,8));
// console.log(funcUpdate(2,3,5,6,7,8,9));

// 惰性载入函数
// function foo() {
//     if (a !== b) {
//         console.log('aaa')
//     } else {
//         console.log('bbb')
//     }
// }
// 优化后    
// function foo() {
//     if (a != b) {
//         foo = function () {
//             console.log('aaa')
//         }
//     } else {
//         foo = function () {
//             console.log('bbb')
//         }
//     }
//     return foo();
// }
// let a = 1;
// let b = 2;
// foo();

// 一次性函数
// let sca = ()=>{
//     console.log('sca first')
//     sca = ()=>{
//         console.log('sca second')
//     }
// }


// 字符串比较日期大小
// let a = '2014-02-03 03:00'
// let b = '2015-02-03 15:00'
// console.log(a>b,a<b);
// console.log("21:00"<"09:10"); // false
// console.log("21:00"<"9:10"); // true 时间形式注意补0

// 数字
// 1 进制表示法
// console.log(29)   //
// console.log(035)  // 
// console.log(0o35) //  八进制数
// console.log(0x1d) // 十六进制

// 精确到指定位数的小数
// // 将数字的四舍五入到指定的小数位数。使用Math.round
// const round = (n, decimals = 0) => Number(`${Math.round(`${n}e${decimals}`)}e-${decimals}`)
// console.log(round(1.36592,3));
// console.log(Number(1366+`e-2`))
// console.log(Number(Math.round(`1.356e2`)+`e-2`))

// 数字前补0的操作
// const addZero1 = (num, len = 2) => (`0${num}%`).slice(-len)
// console.log(addZero1(5,3));
// const addZero2 = (num, len = 2) => (`${num}%`).padStart( len , '0')
// console.log(addZero2(19,3))
// console.log(addZero2(0.19,3))

// 数组
// reduce方法同时实现map和filter

// const numbers = [10, 20, 30, 40];
// const doubledOver50 = numbers.reduce((finalList, num) => {
//     num = num * 2;
//     if (num > 50) {
//         finalList.push(num);
//     }
//     return finalList;
// }, []);
// console.log(doubledOver50);

// 统计数组中相同项的个数
// 统计数组中重复出现项的个数然后用一个对象表示。那么你可以使用reduce方法处理这个数组

// 统计数组中相同项的个数
// var cars = ['BMW', 'Benz', 'Benz', 'Tesla', 'BMW', 'Toyota'];
// var carsObj = cars.reduce(function (obj, name) {
//     obj[name] = obj[name] ? ++obj[name] : 1;
//     return obj;
// }, {});
// console.log(carsObj); // => { BMW: 2, Benz: 2, Tesla: 1, Toyota: 1 }

// 使用解构来交换参数数值
// 函数返回的多个值放在一个数组里。我们可以使用数组解构来获取其中每一个值
// let param1 = 1;
// let param2 = 2;
// [param1, param2] = [param2, param1];
// console.log(param1) // 2
// console.log(param2) // 1

// 其他交换两值的办法
// var temp = a; a = b; b = temp;
// b = [a, a = b][0];
// a = a + b; b = a - b; a = a - b;

// 接收函数返回的多个结果
// 在下面的代码中，我们从/post中获取一个帖子，然后在/comments中获取相关评论。由于我们使用的是async/await，函数把返回值放在一个数组中。而我们使用数组解构后就可以把返回值直接赋给相应的变量

// async function getFullPost(){
//     return await Promise.all([    
//     fetch('/post'),    
//     fetch('/comments')    
//     ]);    
//     }    
// const [post, comments] = getFullPost();

// 将数组平铺到指定深度 使用递归，为每个深度级别 depth 递减 1 。使用 Array.reduce() 和 Array.concat() 来合并元素或数组。基本情况下， depth 等于 1 停止递归。省略第二个参数， depth 只能平铺到 1 (单层平铺) 的深度
// const flatten = (arr, depth = 1) =>
// depth != 1
// ? arr.reduce((a, v) => a.concat(Array.isArray(v) ? flatten(v, depth - 1) : v), [])
// : arr.reduce((a, v) => a.concat(v), []);

// flatten([1, [2], 3, 4]); // [1, 2, 3, 4]
// flatten([1, [2, [3, [4, 5], 6], 7], 8], 2); // [1, 2, 3, [4, 5], 6, 7, 8]

// 数组的对象解构
// const csvFileLine = '1997,John Doe,US,john@doe.com,New York';
// const { 2: country, 4: state } = csvFileLine.split(',');
// console.log(country) // US
// console.log(state) // New Yourk


// 对象
// 使用解构删除不必要属性
// let {_internal, tooBig, ...cleanObject} = {el1: '1', _internal:"secret", tooBig:{}, el2: '2', el3: '3'};
// console.log(cleanObject); 

// 在函数参数中解构嵌套对象 engine是对象car中嵌套的一个对象。如果我们对engine的vin属性感兴趣，使用解构赋值可以很轻松地得到它

var car = {
    model: 'bmw 2018',
    engine: {
        v6: true,
        turbo: true,
        vin: 12345
    }
}
const modelAndVIN = ({
    model,
    engine: {
        vin
    }
}) => {
    console.log(`model: ${model} vin: ${vin}`);
}
modelAndVIN(car); // => model: bmw 2018 vin: 12345